package com.flying.flow.service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import com.flying.common.annotation.DaoCreate;
import com.flying.common.annotation.DaoQuery;
import com.flying.common.annotation.DaoRemove;
import com.flying.common.annotation.DaoUpdate;
import com.flying.common.service.SequenceService;
import com.flying.common.util.Codes;
import com.flying.flow.model.FlowInstance;
import com.flying.flow.model.FlowInstance.FlowInstanceStatus;
import com.flying.flow.model.Node.EmergencyLevel;
import com.flying.flow.model.Node.PriorityLevel;
import com.flying.flow.model.Task.TaskStatus;
import com.flying.flow.model.Task;
import com.flying.framework.annotation.MethodInfo;
import com.flying.framework.annotation.Param;
import com.flying.framework.annotation.Service;
import com.flying.framework.context.ServiceContext;
import com.flying.framework.exception.AppException;
import com.flying.framework.model.ActionResult;
import com.flying.framework.model.ModelFactory;
import com.flying.framework.model.QueryResult;
import com.flying.framework.security.Principal;
import com.flying.framework.service.AbstractService;

@Service(value="FlowInstanceService", desc="流程实例")
public class FlowInstanceService extends AbstractService{
    private static SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
    
    private SequenceService seq;
    private TaskService ts;
    
    public void setSequenceService(SequenceService s) {
    	this.seq = s;
    }
    
    public void setTaskService(TaskService s) {
    	this.ts = s;
    }
    
	@MethodInfo("新增")
	public FlowInstance create(
			@Param(value=FlowInstance.FLOW_DEF_ID, required=true,	desc="流程定义ID") Long flow_def_id,
			@Param(value=FlowInstance.FLOW_ID, required=true,	desc="流程ID") Long flow_id,
			@Param(value=FlowInstance.ORG_CODE, required=true,	desc="机构代码") String org_code,
			@Param(value=FlowInstance.BUSINESS_TYPE, required=true,	desc="业务类型") String business_type,
			@Param(value=FlowInstance.BUSINESS_CODE, required=true,	desc="业务代码") String business_code,
			@Param(value=FlowInstance.NAME, required=false,	desc="名称") String name,
			@Param(value=FlowInstance.REMARKS, required=false,	desc="说明") String remarks,
			@Param(value=FlowInstance.PRIORITY_LEVEL, required=false,enumClass=PriorityLevel.class,	desc="优先级别") Integer priority_level,
			@Param(value=FlowInstance.EMERGENCY_LEVEL, required=false, enumClass=EmergencyLevel.class,	desc="紧急程度") Integer emergency_level
		) throws Exception {
		Principal p = ServiceContext.getContext().getPrincipal();
		String order_no = String.valueOf(seq.nextLong(org_code+"_"+business_type));
		while(order_no.length() < 5) {
			order_no = "0" + order_no;
		}
		order_no = org_code + business_type + df.format(new Date()) + order_no;
		return this.create2(flow_def_id, flow_id, org_code, business_type, business_code, name, remarks, order_no, 
				priority_level, emergency_level, FlowInstanceStatus.PROCESSING.value(), new Date(), p == null?null: p.getName(), new Date());
	}
    
	@MethodInfo("新增")
	@DaoCreate(entity=FlowInstance.ENTITY_NAME)
	protected FlowInstance create2(
			@Param(value=FlowInstance.FLOW_DEF_ID, required=true,	desc="流程定义ID") Long flow_def_id,
			@Param(value=FlowInstance.FLOW_ID, required=true,	desc="流程ID") Long flow_id,
			@Param(value=FlowInstance.ORG_CODE, required=true,	desc="机构代码") String org_code,
			@Param(value=FlowInstance.BUSINESS_TYPE, required=true,	desc="业务类型") String business_type,
			@Param(value=FlowInstance.BUSINESS_CODE, required=true,	desc="业务代码") String business_code,
			@Param(value=FlowInstance.NAME, required=false,	desc="名称") String name,
			@Param(value=FlowInstance.REMARKS, required=false,	desc="说明") String remarks,
			@Param(value=FlowInstance.ORDER_NO, required=false,	desc="工单号") String order_no,
			@Param(value=FlowInstance.PRIORITY_LEVEL, required=false,enumClass=PriorityLevel.class,	desc="优先级别") Integer priority_level,
			@Param(value=FlowInstance.EMERGENCY_LEVEL, required=false, enumClass=EmergencyLevel.class,	desc="紧急程度") Integer emergency_level,
			@Param(value=FlowInstance.STATUS, required=false, enumClass=FlowInstanceStatus.class,	desc="状态") Integer status,
			@Param(value=FlowInstance.START_TIME, required=false,	desc="开始时间") Date start_time,
			@Param(value=FlowInstance.CREATOR, required=false,	desc="创建人") String creator,
			@Param(value=FlowInstance.CREATE_TIME, required=false,	desc="创建时间") Date create_time
		) throws Exception {
		return null;
	}

	@MethodInfo("修改")
	@DaoUpdate(entity=FlowInstance.ENTITY_NAME)
	public ActionResult update(
			@Param(value=FlowInstance.FLOW_INSTANCE_ID, required=true,	desc="流程实例ID") Long flow_instance_id,
			@Param(value=FlowInstance.NAME, required=false,	desc="名称") String name,
			@Param(value=FlowInstance.REMARKS, required=false,	desc="说明") String remarks,
			@Param(value=FlowInstance.EMERGENCY_LEVEL, required=false, enumClass=EmergencyLevel.class,	desc="紧急程度") Integer emergency_level,
			@Param(value=FlowInstance.PRIORITY_LEVEL, required=false,enumClass=PriorityLevel.class,	desc="优先级别") Integer priority_level,
			@Param(value=FlowInstance.UPDATE_TIME, required=false,	desc="修改时间") Date update_time,
			@Param(value=FlowInstance.UPDATOR, required=false,	desc="修改人") String updator
		) throws Exception {
		FlowInstance fi = this.findById(flow_instance_id);
		if(fi.getStatus() == FlowInstanceStatus.FAIL.value() || fi.getStatus() == FlowInstanceStatus.SUCCESS.value()) {
			throw new AppException("0101","流程已经结束，不能继续修改！");
		}
		Principal p = ServiceContext.getContext().getPrincipal();
		return ModelFactory.create(ActionResult.class, 
				FlowInstance.UPDATOR, (p == null?null: p.getName()),
				FlowInstance.UPDATE_TIME, new Date());
	}

	@MethodInfo("修改")
	@DaoUpdate(entity=FlowInstance.ENTITY_NAME)
	protected ActionResult updateStartStatus(
			@Param(value=FlowInstance.FLOW_INSTANCE_ID, required=true,	desc="流程实例ID") Long flow_instance_id,
			@Param(value=FlowInstance.STATUS, required=true, enumClass=FlowInstanceStatus.class,	desc="状态") Integer status,
			@Param(value=FlowInstance.START_TIME, required=false,	desc="开始时间") Date start_time,
			@Param(value=FlowInstance.UPDATE_TIME, required=false,	desc="修改时间") Date update_time,
			@Param(value=FlowInstance.UPDATOR, required=false,	desc="修改人") String updator
		) throws Exception {
		Principal p = ServiceContext.getContext().getPrincipal();
		return ModelFactory.create(ActionResult.class, 
				FlowInstance.UPDATOR, (p == null?null: p.getName()),
				FlowInstance.UPDATE_TIME, new Date());
	}

	@MethodInfo("修改")
	public ActionResult start(
			@Param(value=FlowInstance.FLOW_INSTANCE_ID, required=true,	desc="流程实例ID") Long flow_instance_id
		) throws Exception {
		return this.updateStartStatus(flow_instance_id, FlowInstanceStatus.PROCESSING.value(), new Date(), null, null);
	}

	@MethodInfo("修改")
	@DaoUpdate(entity=FlowInstance.ENTITY_NAME)
	protected ActionResult updateFinishStatus(
			@Param(value=FlowInstance.FLOW_INSTANCE_ID, required=true,	desc="流程实例ID") Long flow_instance_id,
			@Param(value=FlowInstance.STATUS, required=true, enumClass=FlowInstanceStatus.class,	desc="状态") Integer status,
			@Param(value=FlowInstance.FINISH_TIME, required=false,	desc="完成时间") Date finish_time,
			@Param(value=FlowInstance.CONSUME_SECONDS, required=false,	desc="耗时") Integer consume_seconds,
			@Param(value=FlowInstance.UPDATE_TIME, required=false,	desc="修改时间") Date update_time,
			@Param(value=FlowInstance.UPDATOR, required=false,	desc="修改人") String updator
		) throws Exception {
		Principal p = ServiceContext.getContext().getPrincipal();
		return ModelFactory.create(ActionResult.class, 
				FlowInstance.UPDATOR, (p == null?null: p.getName()),
				FlowInstance.UPDATE_TIME, new Date());
	}

	@MethodInfo("修改")
	public ActionResult finish(
			@Param(value=FlowInstance.FLOW_INSTANCE_ID, required=true,	desc="流程实例ID") Long flow_instance_id,
			@Param(value=FlowInstance.STATUS, required=true, enumClass=FlowInstanceStatus.class,	desc="状态") Integer status
		) throws Exception {
		List<Task> tasks = this.ts.findByFlowInstanceId(flow_instance_id, new Integer[] {TaskStatus.FINISHED.value()}).getRows();
		Long consume_seconds = tasks.stream().mapToLong(x -> (x.getActualEnd().getTime() - x.getActualStart().getTime())).sum() / 1000;
		return this.updateFinishStatus(flow_instance_id, status, new Date(), consume_seconds.intValue(), null, null);
	}

	@MethodInfo("删除")
	@DaoRemove(entity=FlowInstance.ENTITY_NAME)
	public ActionResult remove(
			@Param(value=FlowInstance.FLOW_INSTANCE_ID, required=true,	desc="流程实例ID") Long flow_instance_id
		) throws Exception {
		return null;
	}

	@MethodInfo("搜索")
	@DaoQuery(entity=FlowInstance.ENTITY_NAME, pageable=true, modelClass=FlowInstance.class, osql="order by t.create_time desc")
	public QueryResult<FlowInstance> findByParticipant(
			@Param(value=FlowInstance.BUSINESS_TYPE, required=false,	desc="业务类型") String business_type,
			@Param(value=FlowInstance.BUSINESS_CODE, required=false,	desc="业务代码") String business_code,
			@Param(value=FlowInstance.NAME, required=false,	desc="名称", tag="LIKE") String name,
			@Param(value=FlowInstance.PRIORITY_LEVEL, required=false,enumClass=PriorityLevel.class,	desc="优先级别") Integer priority_level,
			@Param(value=FlowInstance.EMERGENCY_LEVEL, required=false, enumClass=EmergencyLevel.class,	desc="紧急程度") Integer emergency_level,
			@Param(value=FlowInstance.STATUS, required=false, enumClass=FlowInstanceStatus.class,	desc="状态") Integer status,
			@Param(value=Task.PARTICIPANT_ID, required=true,	desc="执行人", tag="replace") String participant_id,
			@Param(value=Codes.PAGE_NUM, 	required=false, desc="分页页号，默认0") int page,
			@Param(value=Codes.PAGE_SIZE, 	required=false, desc="分页大小，默认10") int rows) throws Exception {
		return null;
	}

	@MethodInfo("搜索")
	public QueryResult<FlowInstance> findMyFlowInstances(
			@Param(value=FlowInstance.BUSINESS_TYPE, required=false,	desc="业务类型") String business_type,
			@Param(value=FlowInstance.BUSINESS_CODE, required=false,	desc="业务代码") String business_code,
			@Param(value=FlowInstance.NAME, required=false,	desc="名称", tag="LIKE") String name,
			@Param(value=FlowInstance.PRIORITY_LEVEL, required=false,enumClass=PriorityLevel.class,	desc="优先级别") Integer priority_level,
			@Param(value=FlowInstance.EMERGENCY_LEVEL, required=false, enumClass=EmergencyLevel.class,	desc="紧急程度") Integer emergency_level,
			@Param(value=FlowInstance.STATUS, required=false, enumClass=FlowInstanceStatus.class,	desc="状态") Integer status,
			@Param(value=Task.PARTICIPANT_ID, required=false,	desc="执行人", tag="replace") String participant_id,
			@Param(value=Codes.PAGE_NUM, 	required=false, desc="分页页号，默认0") int page,
			@Param(value=Codes.PAGE_SIZE, 	required=false, desc="分页大小，默认10") int rows) throws Exception {
		Principal p = ServiceContext.getContext().getPrincipal();
		return this.findByParticipant(business_type, business_code, name, priority_level, emergency_level, status, p.getName(), page, rows);
	}

	@MethodInfo("搜索")
	@DaoQuery(entity=FlowInstance.ENTITY_NAME, pageable=true, modelClass=FlowInstance.class, osql="order by t.create_time desc")
	public QueryResult<FlowInstance> findAll(
			@Param(value=FlowInstance.ORG_CODE, required=false,	desc="机构代码") String org_code,
			@Param(value=FlowInstance.BUSINESS_TYPE, required=false,	desc="业务类型") String business_type,
			@Param(value=FlowInstance.BUSINESS_CODE, required=false,	desc="业务代码") String business_code,
			@Param(value=FlowInstance.NAME, required=false,	desc="名称", tag="LIKE") String name,
			@Param(value=FlowInstance.PRIORITY_LEVEL, required=false,enumClass=PriorityLevel.class,	desc="优先级别") Integer priority_level,
			@Param(value=FlowInstance.EMERGENCY_LEVEL, required=false, enumClass=EmergencyLevel.class,	desc="紧急程度") Integer emergency_level,
			@Param(value=FlowInstance.STATUS, required=false, enumClass=FlowInstanceStatus.class,	desc="状态") Integer status,
			@Param(value=Codes.PAGE_NUM, 	required=false, desc="分页页号，默认0") int page,
			@Param(value=Codes.PAGE_SIZE, 	required=false, desc="分页大小，默认10") int rows) throws Exception {
		return null;
	}

	@MethodInfo("查询")
	@DaoQuery(entity=FlowInstance.ENTITY_NAME, single=true, throwsNotFoundException=true )
	public FlowInstance findById(
			@Param(value=FlowInstance.FLOW_INSTANCE_ID, required=true,	desc="流程实例ID") Long flow_instance_id
		) throws Exception {
		return null;
	}

}